/**
 * 
 */
package de.dnb.gnd.utils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.naming.OperationNotSupportedException;

import de.dnb.basics.applicationComponents.RangeCheckUtils;
import de.dnb.basics.filtering.IPredicate;
import de.dnb.gnd.exceptions.IllFormattedLineException;
import de.dnb.gnd.parser.Format;
import de.dnb.gnd.parser.Record;
import de.dnb.gnd.parser.Subfield;
import de.dnb.gnd.parser.line.Line;
import de.dnb.gnd.parser.line.LineParser;
import de.dnb.gnd.parser.tag.GNDTag;
import de.dnb.gnd.parser.tag.GNDTagDB;
import de.dnb.gnd.parser.tag.Tag;

/**
 * Enthält spezielle Hilfsfunktionen für die Satzart Tu.
 * 
 * @author baumann
 *
 */
public final class WorkUtils {

	private static final GNDTagDB TAG_DB = GNDTagDB.getDB();

	private static final Tag TAG_130 = TAG_DB.findTag("130");

	private static final List<String> ALLOWED_TAGS = Arrays
		.asList("130", "430");;

	private WorkUtils() {
		super();
		// TODO Auto-generated constructor stub
	}

	public static boolean isWork(Record record) {
		RangeCheckUtils.assertReferenceParamNotNull("record", record);
		return (RecordUtils.getDatatypeCharacterAt(record, 0) == 'T' && RecordUtils
			.getDatatypeCharacterAt(record, 1) == 'u');
	}

	/**
	 * Gibt die Zeile mit dem Titel des Werkes.
	 * 
	 * @param record	nicht null.
	 * @return			Den Titel. Wenn keiner vorhanden wird eine
	 * 					IllegalStateException geworfen.
	 */
	public static Line getTitleLine(final Record record) {
		Line titleLine = RecordUtils.getTheOnlyLine(record, TAG_130);
		if (titleLine == null)
			throw new IllegalStateException("Keine 130.");
		else
			return titleLine;
	}

	/**
	 * Gibt den Titel des Werkes im Pica3-Format mit Unterfeldern. 
	 * Kommentare werden vorher entfernt.
	 * 
	 * @param record	nicht null.
	 * @return			Den Titel. Wenn keiner vorhanden wird eine
	 * 					IllegalStateException geworfen.
	 */
	public static String getNormedTitle(final Record record) {
		Line titleLine = getTitleLine(record);
		return normalizeTitelLine(titleLine);
	}

	/**
	 * Gibt den Titel des Werkes im Pica3-Format, wie er in $8
	 * angezeigt würde.
	 * 
	 * @param record	nicht null.
	 * @return			Den Titel. Wenn keiner vorhanden ist oder mehrere
	 * 					erste Autoren vorhanden sind, wird eine
	 * 					IllegalStateException geworfen.
	 */
	public static String getExpansionTitle(final Record record) {
		String title = getNormedTitle(record);
		Line authorLine = getAuthor(record);
		if (authorLine != null) {
			title = GNDUtils.getNameOfRelatedRecord(authorLine) + "$a" + title;
		}
		return title;

	}

	/**
	 * Gibt den Titel als String ohne störende Unterfelder $4, $5, $v.
	 * 
	 * @param line	nicht null, als GNDTag nur 130 und 430 zugelassen.
	 * @return		Titel im Pica3-Format. Kann $-Zeichen enthalten.
	 */
	public static String normalizeTitelLine(final Line line) {
		List<Subfield> subfields =
			SubfieldUtils.getNamingRelevantSubfields(line);
		String normedTitle =
			RecordUtils.toPicaWithoutTag(TAG_130, subfields, Format.PICA3,
				false, '$');
		return normedTitle;
	}

	/**
	 * Liefert eine Liste von Unterfeldern aus dem Werktitel ohne
	 * störende Unterfelder $4, $5, $v.
	 * 
	 * @param 	record	nicht null.
	 * @return			Liste.	
	 */
	public static List<Subfield> normalizedSubfields(Record record) {
		GNDUtils.assertGNDRecord(record);
		Line line = getTitleLine(record);
		return SubfieldUtils.getNamingRelevantSubfields(line);
	}

	/**
	 * Gibt die Zeile mit dem einzigen ersten Verfasser.
	 * 
	 * @param record	nicht null.
	 * @return			Den einzigen ersten Verfasser, Künstler oder 
	 * 					Komponisten, null bei anonymen Werken. 
	 * 					Sollten mehrere erste Verfasser existieren, wird eine
	 * 					IllegalStateException geworfen.
	 */
	public static Line getAuthor(final Record record) {
		GNDUtils.assertGNDRecord(record);
		IPredicate<Line> predicate = new IPredicate<Line>() {
			@Override
			public boolean accept(final Line line) {
				if (SubfieldUtils.containsIndicator(line, '4')) {
					Subfield subfield4 =
						SubfieldUtils.getFirstSubfield(line, '4');
					String subCont = subfield4.getContent();
					return subCont.equals("aut1") || subCont.equals("kom1")
						|| subCont.equals("kue1");
				} else
					return false;
			}
		};
		Collection<Tag> gndTags = TAG_DB.getRelatedTag5XX();
		List<Line> lines = RecordUtils.getLines(record, predicate, gndTags);
		if (lines.isEmpty())
			return null;
		else if (lines.size() != 1)
			throw new IllegalStateException("Mehrere erste Autoren in idn: "
				+ record.getId());
		else {
			Line line = lines.get(0);
			return line;
		}
	}

	/**
	 * Gibt die idn des einzigen ersten Verfassers.
	 * 
	 * @param record	nicht null.
	 * @return			Die idn des einzigen ersten Verfassers, Künstlers oder 
	 * 					Komponisten, sofern relationiert. Ansonsten null.
	 * 					Sollten mehrere erste Verfasser existieren, wird eine
	 * 					IllegalStateException geworfen.
	 */
	public static String getAuthorID(final Record record) {
		GNDUtils.assertGNDRecord(record);
		Line line = getAuthor(record);
		if (line == null)
			return null;
		else {
			return line.getIdnRelated();
		}
	}

	/**
	 * Liefert eine Liste der alten Werktitel ohne Komponisten aus der 913.
	 * <br><br>
	 * Die 913 enthält in der Regel eine Boilerplate
	 * 	"913 $Sswd$ipt$a". 
	 * Dann folgt der eventuelle Komponist, gefolgt von
	 * 	", ", 
	 * danach der Titel, danach die alte nid 
	 * 	"$04425694-2".
	 * 
	 * Also z.B.
	 * <br><br>913 $Sswd$it$aMagnus liber <Musik>$04759556-5
	 * @param record	nicht null.
	 * @return Liste der Werktitel, eventuell leer.
	 */
	public static ArrayList<String> getOriginalTitles(final Record record) {
		GNDUtils.assertGNDRecord(record);
		List<String> headings = GNDUtils.getOriginalHeadings(record);
		ArrayList<String> titles = new ArrayList<String>();
		for (String heading : headings) {
			String[] parts = heading.split(": ");
			if (parts.length == 2) {
				titles.add(parts[1].replace("{", ""));
			} else
				titles.add(heading.replace("{", ""));
		}
		return titles;
	}

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		Record record = GNDUtils.readFromClip();
		System.out.println(getExpansionTitle(record));
	}

	/**
	 * @param args
	 * @throws IllFormattedLineException 
	 * @throws OperationNotSupportedException 
	 * @throws IOException 
	 */
	public static void main2(final String[] args)
		throws IllFormattedLineException,
		OperationNotSupportedException,
		IOException {
		final Line line =
			LineParser.parse("430 NWoFG$5abku", GNDTagDB.getDB(), false);
		System.out.println(normalizeTitelLine(line));
	}

}
